表單是網站中,收集使用者資料的主要方式,例如我們常登入社群所需要的帳號密碼,甚至是貼文底下的留言,都是一種表單。
React 的表單和一般 HTML 表單不同,React 是透過 state 管理輸入值,讓資料與 UI 同步。
| 一般 HTML 表單 | React 表單 | |
|---|---|---|
| 資料存放位置 | 值存在 DOM,需要用 document.querySelector 或 e.target.value 取得 | 
值存在 state,由 React 管理 | 
| UI 與資料同步 | UI 自動更新,但程式要額外從 DOM 取值 | UI 與 state 綁定在一起,輸入時 onChange 同時更新 state  | 
| 送出方式 | 重新整理頁面,送到指定的 action URL | 常用 onSubmit 攔截 e.preventDefault(),再用 fetch / axios 請求 API | 
| 驗證 | 使用 required、pattern 等 HTML 屬性 | 
可自定邏輯,或用套件 (Formik、React Hook Form) | 
| 控制方式 | 天生是非受控(值存在 DOM) | 可選擇受控(值放在 state) 或 非受控(用 ref 抓 DOM) | 
(後續文章會介紹到驗證及控制方式)
const [title, setTitle] = useState("");
useState 為表單中每個欄位建立自己的 state<input 
  type="text" 
  required 
  value={title}
  onChange={(e) => setTitle(e.target.value)}
/>
value={title}:此欄位的值綁定到 title 這個 stateonChange={(e) => setTitle(e.target.value)}:每當使用者輸入時,React 會即時更新 stateinput 是 受控元件 (Controlled Component),因為它輸入值轉而由 React 的 state 掌控,並且透過 onChange 即時更新 state。
搭配 onSubmit,使用者點擊新增時,執行送出事件
const handleSubmit = (e) => {
  e.preventDefault();
  const blog = { title };
  console.log(blog);
};
e.preventDefault():避免送出表單時重新刷新整個頁面const blog = { title }:建立一個 blog 物件,把 state ( title )收集起來console.log(blog) 測試,之後可以改成用 fetch API 的方式(POST 請求),把資料存到資料庫<form onSubmit={handleSubmit}>
  <label>Blog title:</label>
  <input
    type="text"
    required
    value={title}
    onChange={(e) => setTitle(e.target.value)} 
   />
  <button>新增</button>
</form>
<form onSubmit={handleSubmit}>:form 的 onSubmit 屬性會在表單送出時觸發 handleSubmit 函式button 預設是 type="submit",點擊時會觸發表單送出事件import { useState } from "react";
const Create = () => {
  const [title, setTitle] = useState("");
  const [body, setBody] = useState("");
  const [author, setAuthor] = useState("");
  const handleSubmit = (e) => {
    e.preventDefault();
    const blog = { title, body, author };
    console.log(blog);
  }
  return (
    <div className="create">
      <h2>新增 Blog</h2>
      <form onSubmit={handleSubmit}>
        <label>Blog title:</label>
        <input 
          type="text" 
          required 
          value={title}
          onChange={(e) => setTitle(e.target.value)}
        />
        <label>Blog body:</label>
        <textarea
          value={body}
          onChange={(e) => setBody(e.target.value)}
        ></textarea>
        <label>Blog author:</label>
        <input
          type="text"
          required
          value={author}
          onChange={(e) => setAuthor(e.target.value)}
        >
        </input>
        <button>新增</button>
      </form>
    </div>
  );
}
 
export default Create;
瀏覽器執行畫面